<?php
/**
 *      [迷你云] (C)2009-2012 南京恒为网络科技.
 *   软件仅供研究与学习使用，如需商用，请访问www.miniyun.cn获得授权
 * 
 */
?>
<?php

Yii::import('application.extensions.image.Image_Driver');


class Image {

		const NONE = 1;
	const AUTO = 2;
	const HEIGHT = 3;
	const WIDTH = 4;
		const HORIZONTAL = 5;
	const VERTICAL = 6;

		public static $allowed_types = array
	(
		IMAGETYPE_GIF => 'gif',
		IMAGETYPE_JPEG => 'jpg',
		IMAGETYPE_PNG => 'png',
		IMAGETYPE_TIFF_II => 'tiff',
		IMAGETYPE_TIFF_MM => 'tiff',
	);

		protected $driver;

		protected $actions = array();

		protected $image = '';

	
	public static function factory($image, $config = NULL)
	{
		return new Image($image, $config);
	}

	
	public function __construct($image, $config = NULL)
	{
		static $check;

				($check === NULL) and $check = function_exists('getimagesize');

		if ($check === FALSE)
			throw new CException('image getimagesize missing');

				if ( ! is_file($image))
			throw new CException('image file not found');

				$ER = error_reporting(0);

				$image_info = getimagesize($image);

				error_reporting($ER);

				if ( ! is_array($image_info) OR count($image_info) < 3)
			throw new CException('image file unreadable');

				if ( ! isset(Image::$allowed_types[$image_info[2]]))
			throw new CException('image type not allowed');

				$this->image = array
		(
			'file' => str_replace('\\', '/', realpath($image)),
			'width' => $image_info[0],
			'height' => $image_info[1],
			'type' => $image_info[2],
			'ext' => Image::$allowed_types[$image_info[2]],
			'mime' => $image_info['mime']
		);

		        if ($config === null){
            $this->config = array(
                'driver'=>'GD',
                'params'=>array(),
            );
        }
        else{
            $this->config = $config;
        }

				$driver = 'Image_'.ucfirst($this->config['driver']).'_Driver';

                Yii::import("application.extensions.image.drivers.$driver");

				$this->driver = new $driver($this->config['params']);

				if ( ! ($this->driver instanceof Image_Driver))
			throw new CException('image driver must be implement Image_Driver class');
	}

	
	public function __get($property)
	{
		if (isset($this->image[$property]))
		{
			return $this->image[$property];
		}
		else
		{
			throw new CException('invalid property');
		}
	}

	
	public function resize($width, $height, $master = NULL)
	{
		if ( ! $this->valid_size('width', $width))
			throw new CException('image invalid width');

		if ( ! $this->valid_size('height', $height))
			throw new CException('image invalid height');

		if (empty($width) AND empty($height))
			throw new CException('image invalid dimensions');

		if ($master === NULL)
		{
						$master = Image::AUTO;
		}
		elseif ( ! $this->valid_size('master', $master))
			throw new CException('image invalid master');

		$this->actions['resize'] = array
		(
			'width'  => $width,
			'height' => $height,
			'master' => $master,
		);

		return $this;
	}

    
	public function crop($width, $height, $top = 'center', $left = 'center')
	{
		if ( ! $this->valid_size('width', $width))
			throw new CException('image invalid width', $width);

		if ( ! $this->valid_size('height', $height))
			throw new CException('image invalid height', $height);

		if ( ! $this->valid_size('top', $top))
			throw new CException('image invalid top', $top);

		if ( ! $this->valid_size('left', $left))
			throw new CException('image invalid left', $left);

		if (empty($width) AND empty($height))
			throw new CException('image invalid dimensions');

		$this->actions['crop'] = array
		(
			'width'  => $width,
			'height' => $height,
			'top'    => $top,
			'left'   => $left,
		);

		return $this;
	}

    
	public function rotate($degrees)
	{
		$degrees = (int) $degrees;

		if ($degrees > 180)
		{
			do
			{
								$degrees -= 360;
			}
			while($degrees > 180);
		}

		if ($degrees < -180)
		{
			do
			{
								$degrees += 360;
			}
			while($degrees < -180);
		}

		$this->actions['rotate'] = $degrees;

		return $this;
	}

    
	public function flip($direction)
	{
		if ($direction !== self::HORIZONTAL AND $direction !== self::VERTICAL)
			throw new CException('image invalid flip');

		$this->actions['flip'] = $direction;

		return $this;
	}

    
	public function quality($amount)
	{
		$this->actions['quality'] = max(1, min($amount, 100));

		return $this;
	}

	
	public function sharpen($amount)
	{
		$this->actions['sharpen'] = max(1, min($amount, 100));

		return $this;
	}

	
	public function save($new_image = FALSE, $chmod = 0644, $keep_actions = FALSE)
	{
				empty($new_image) and $new_image = $this->image['file'];

				$dir  = pathinfo($new_image, PATHINFO_DIRNAME);
		$file = pathinfo($new_image, PATHINFO_BASENAME);

				$dir = str_replace('\\', '/', realpath($dir)).'/';

		if ( ! is_writable($dir))
			throw new CException('image directory unwritable');

		if ($status = $this->driver->process($this->image, $this->actions, $dir, $file))
		{
			if ($chmod !== FALSE)
			{
								chmod($new_image, $chmod);
			}
		}
		
				if ($keep_actions === FALSE)
			$this->actions = array();
		
		return $status;
	}
	
	 
	public function render($keep_actions = FALSE) 
	{ 
		$new_image = $this->image['file']; 
	
				$dir  = pathinfo($new_image, PATHINFO_DIRNAME); 
		$file = pathinfo($new_image, PATHINFO_BASENAME); 
	
				$dir = str_replace('\\', '/', realpath($dir)).'/'; 
	
				$status = $this->driver->process($this->image, $this->actions, $dir, $file, $render = TRUE); 
		
				if ($keep_actions === FALSE)
			$this->actions = array();
		
		return $status; 
	}
    
	
	public function render_direct($is_direct = TRUE, $keep_actions = FALSE) {
	    $offset = 60*60*24*30;         $ExpStr = "Expires: ".gmdate("D, d M Y H:i:s", time() + $offset)." GMT";
        header($ExpStr);
	    header('Cache-Control: public' );
	    header('Pragma: cache');
	    header('Last-Modified: '.gmdate("D, d M Y H:i:s", time() + $offset)." GMT");
	    header('ETag: ' . md5($_SERVER['REQUEST_URI']));
	    if ($is_direct === TRUE) {
	        $new_image = $this->image['file'];
	        $contents = file_get_contents($new_image);
	        $ext = substr($new_image, strrpos($new_image, '.') + 1);
			switch (strtolower($ext))
			{
				case 'jpg':
				case 'jpeg':
					header('Content-Type: image/jpeg');
				break;
				case 'gif':
					header('Content-Type: image/gif');
				break;
				case 'png':
					header('Content-Type: image/png');
				break;
			}
			echo $contents;
			if ($keep_actions === FALSE){
			    $this->actions = array();
			}
			    
			return true;
	    } else {
	        return $this->render($keep_actions);
	    }
	}
	
	
	protected function valid_size($type, & $value)
	{
		if (is_null($value))
			return TRUE;

		if ( ! is_scalar($value))
			return FALSE;

		switch ($type)
		{
			case 'width':
			case 'height':
				if (is_string($value) AND ! ctype_digit($value))
				{
										if ( ! preg_match('/^[0-9]++%$/D', $value))
						return FALSE;
				}
				else
				{
					$value = (int) $value;
				}
			break;
			case 'top':
				if (is_string($value) AND ! ctype_digit($value))
				{
					if ( ! in_array($value, array('top', 'bottom', 'center')))
						return FALSE;
				}
				else
				{
					$value = (int) $value;
				}
			break;
			case 'left':
				if (is_string($value) AND ! ctype_digit($value))
				{
					if ( ! in_array($value, array('left', 'right', 'center')))
						return FALSE;
				}
				else
				{
					$value = (int) $value;
				}
			break;
			case 'master':
				if ($value !== Image::NONE AND
				    $value !== Image::AUTO AND
				    $value !== Image::WIDTH AND
				    $value !== Image::HEIGHT)
					return FALSE;
			break;
		}

		return TRUE;
	}
    
	public function getImage() {
	    return $this->image;
	}
} 